#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Script: py-konto.py
(GUI version of py_konto_main.py)
Reads a downloaded IFXXML file from UniCredit (BankAustria(AT))
and exports it to ofx format.
"""

# Imports
import sys
import os
import os.path
import glob
import string
import argparse
import hashlib
import shutil
import ConfigParser
from lxml import etree as et

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import ui_py_konto_dlg

MAC = "qt_mac_set_native_menubar" in dir()  # check if Apple Mac platform

class mainDialog(QDialog, ui_py_konto_dlg.Ui_mainDialog):
    """
    Class which builds the main (and only) GUI- QDialog of the script
    @param ifxfile: filename of the ifx infile
    """
    def __init__(self, ifxfile, parent=None):
        super(mainDialog, self).__init__(parent)

        self.setupUi(self)
        if not MAC:
            self.okButton.setFocusPolicy(Qt.NoFocus)
            self.cancelButton.setFocusPolicy(Qt.NoFocus)

        # Variables
        self._ifxfile = ifxfile
        #self._curdir = ''
        #self._ifxfile = ''
        #self._ofxfile = ''
        self._ifxfile_list = []

        opt = self.readOptionsFile()
        if not opt:
            #self._curdir = os.getenv("HOME")
            self._ifxfile_dir = os.getenv("HOME")
            self._ofxfile_dir = os.getenv("HOME")
            self._ifxfile = ifxfile
            self._ofxfile = "all"
#            self.log("blue", "<b>in if not:</b> " + self._curdir + ', '
#                                                     + self._ifxfile + ', '
#                                                     + self._ofxfile + ';')

        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(50)
        self.progressBar.setValue(0)

#        self.log("blue", "<b>mainDialog():</b> " + self._curdir + ', '
#                                                 + self._ifxfile + ', '
#                                                 + self._ofxfile + ';')

        if self._ifxfile != "all":
            self.singleFileUi()
        elif self._ifxfile == "all":
            self.multiFileUi()

    def singleFileUi(self):
        """
        sets the necessary widgets active - if not all files of cur. dir. are processed
        sets: self._ofxfile
        """
        (self._ifxfile_dir, tmpname) = os.path.split(self._ifxfile)
        (fileBaseName, fileExtension)=os.path.splitext(tmpname)
        self._ofxfile = self._ifxfile_dir + '/ofx/' + fileBaseName + '.ofx'
        if os.path.isfile(self._ofxfile):
            self.log("red", 'OFX file \'' + self._ofxfile + '\' exists!\n')
        self._ofxfile_dir = self._curdir = self._ifxfile_dir
        self.ifxAllCheckBox.setChecked(False)
        self.ifxLineEdit.setEnabled(True)
        self.ifxLineEdit.setText(self._ifxfile)
        self.ifxBrowsePushButton.setEnabled(True)
        self.ofxLineEdit.setEnabled(True)
        self.ofxLineEdit.setText(self._ofxfile)
        self.ofxBrowsePushButton.setEnabled(True)
        self.dirLineEdit.setEnabled(False)
        self.dirLineEdit.setText(self._curdir)
        self.dirBrowsePushButton.setEnabled(False)
        self.saveIfxCheckBox.setEnabled(True)

#        self.log("grey", "IFX- File: " + self._ifxfile)
#        self.log("grey", "OFX- File: " + self._ofxfile)

    def multiFileUi(self):
        self.dirLineEdit.setText(self._curdir)
        self.ifxLineEdit.setText(self._ifxfile)
        self.ofxLineEdit.setText("all")
        self.saveIfxCheckBox.setChecked(False)
        self.saveIfxCheckBox.setEnabled(False)
#        self.log("blue", "<b>multiFileUi():</b> _curdir = " + self._curdir)
        self._ifxfile_list = buildIfxFileTree(unicode(self._curdir))
        self.log("grey", "Number of files to process: " + str(len(self._ifxfile_list)))

    @pyqtSignature("")
    def on_ifxAllCheckBox_clicked(self):
        # ifx checked ...
        if self.ifxAllCheckBox.isChecked():
            self.ifxLineEdit.setEnabled(False)
            self.ofxLineEdit.setEnabled(False)
            self.dirLineEdit.setEnabled(True)
            self.dirBrowsePushButton.setEnabled(True)
            self.dirLineEdit.setText(self._curdir)
            self.ifxLineEdit.setText(self._ifxfile)
            self.ofxLineEdit.setText(self._ofxfile)
            self.saveIfxCheckBox.setChecked(False)
            self.saveIfxCheckBox.setEnabled(False)
            self.ifxBrowsePushButton.setEnabled(False)
            self.okButton.setEnabled(True)
            self.ofxBrowsePushButton.setEnabled(False)
#            self.log("blue", "<b>ifxAllCB(): path =</b> " + self._curdir)
            self._ifxfile_list = buildIfxFileTree(unicode(self._curdir))
            self.log("grey", "Number of files to process: " + str(len(self._ifxfile_list)))
            self.emit(SIGNAL("ifx_all_on"))
#            self.log("blue", "<b>debug: SIGNAL:</b> \'ifx_all_on\' sent.")
            # ofx checked ...
            if self.ofxCheckBox.isChecked():
                self.ofxLineEdit.setText("all")
        # ifx not checked ...
        elif not self.ifxAllCheckBox.isChecked():
            if self.ofxCheckBox.isChecked():
                self.saveIfxCheckBox.setEnabled(True)
                self.dirLineEdit.setEnabled(False)
                self.dirBrowsePushButton.setEnabled(False)
                self.ifxLineEdit.setEnabled(True)
                self.ifxLineEdit.selectAll()
                self.ofxLineEdit.setEnabled(True)
                self.ofxLineEdit.selectAll()
                self.dirLineEdit.setText(self._curdir)
                self.ifxLineEdit.setText(self._ifxfile)
                self.ofxLineEdit.setText(self._ofxfile)
                self.ifxBrowsePushButton.setEnabled(True)
                self.okButton.setEnabled(True)
                self.ofxBrowsePushButton.setEnabled(True)
                self.emit(SIGNAL("ifx_all_off"))
#                self.log("blue", "<b>debug: SIGNAL:</b> \'ifx_all_off\' sent.")
            # ofx not checked ...
            elif not self.ofxCheckBox.isChecked():
                self.okButton.setEnabled(False)
                self.log("red", "<b>Err:</b> \'ifx\' AND \'ofx\' unchecked! Nothing to do for me!")

    @pyqtSignature("")
    def on_ofxCheckBox_clicked(self):       # QtCore.QT.PartiallyChecked
        # ofx not checked ...
        if not self.ofxCheckBox.isChecked():
            self.ofxLineEdit.setEnabled(False)
            self.ofxBrowsePushButton.setEnabled(False)
            self.dirLineEdit.setText(self._curdir)
            self.ifxLineEdit.setText(self._ifxfile)
            self.ofxLineEdit.setText(self._ofxfile)
            self.emit(SIGNAL("ofx_off"))
            # ifx not checked ...
            if not self.ifxAllCheckBox.isChecked():
                self.okButton.setEnabled(False)
                self.log("red", "<b>Err:</b> \'ifx\' AND \'ofx\' unchecked! Nothing to do for me!")
        # ofx checked ...
        elif self.ofxCheckBox.isChecked():
            # ifx not checked ...
            if not self.ifxAllCheckBox.isChecked():
                self.ofxLineEdit.setEnabled(True)
                self.ofxBrowsePushButton.setEnabled(True)
            self.dirLineEdit.setText(self._curdir)
            self.ifxLineEdit.setText(self._ifxfile)
            self.ofxLineEdit.setText(self._ofxfile)
            self.okButton.setEnabled(True)
            self.emit(SIGNAL("ofx_on"))
            #ifx checked ...
            if self.ifxAllCheckBox.isChecked():
                self.ofxLineEdit.setText("all")

    @pyqtSignature("")
    def on_dirBrowsePushButton_clicked(self):
        path = unicode(self.dirLineEdit.text() + '/')
        tmp = unicode(QFileDialog.getExistingDirectory(self, "Select working directory:", path))
        if tmp:
            self._ifxfile_dir = tmp
            self._curdir = tmp
            self._ofxfile_dir = tmp+ '/ofx/'
            pass
#        self.log("blue", "<b>dirBrowsePB(): path=</b> " + path)
        #self._ofxfile_dir = self._ifxfile_dir
#        self.log("grey", "working dir: " + self._curdir)
        self._ifxfile_list = buildIfxFileTree(self._curdir)
        self.log("grey", "Number of files to process: " + str(len(self._ifxfile_list)))
        self.dirLineEdit.setText(self._curdir)
        self.ifxLineEdit.setText(self._ifxfile)
        self.ofxLineEdit.setText(self._ofxfile)

    @pyqtSignature("")
    def on_ifxBrowsePushButton_clicked(self):
        path = self.dirLineEdit.text() + '/'
        tmp  = unicode(QFileDialog.getOpenFileName(self, "Select ifxxml file:", path,
                                                        "IFXXML Files (*.ifxxml);;All Files (*.*)"))
        if tmp:
            self._ifxfile = tmp
            pass
#        self.log("blue", "<b>debug: path=</b> " + path)
#        self.log("blue", "<b>debug: IFX file:</b> " + self._ifxfile)
        self.ifxLineEdit.setText(self._ifxfile)
        (dirName, fileName) = os.path.split(self._ifxfile)
        (fileBaseName, fileExtension)=os.path.splitext(fileName)
        self._ifxfile_dir = self._ofxfile_dir = dirName
        self._ofxfile = dirName + '/ofx/' + fileBaseName + '.ofx'
        self._curdir = self._ifxfile_dir
        if os.path.isfile(self._ofxfile):
            self.log("red", "<b>Warning:</b> OFX file \'" + self._ofxfile + "\' exists!\n")
        self.ofxLineEdit.setText(self._ofxfile)
        self.dirLineEdit.setText(self._curdir)

    @pyqtSignature("")
    def on_ofxBrowsePushButton_clicked(self):
        path = unicode(self.dirLineEdit.text() + "/")
#        self.log("blue", "<b>debug: path= </b>" + path)
        tmp = unicode(QFileDialog.getExistingDirectory(self, "Select directory", path))
        if tmp:
            self._ofxfile_dir = tmp
            pass
        (dirName, fileName) = os.path.split(self._ofxfile)
        self._ofxfile = self._ofxfile_dir + '/' + fileName
#        self.log("blue", "debug: <b>OFX file:</b> " + self._ofxfile)
        if os.path.isfile(self._ofxfile):
            self.log("red", "<b>Warning: </b>OFX file \'" + self._ofxfile + "\' exists!\n")
        self.ofxLineEdit.setText(self._ofxfile)

    @pyqtSignature("")
    def on_okButton_clicked(self):
        #self.emit(SIGNAL("okButton_clicked"), self.process)
        self._curdir = unicode(self.dirLineEdit.text())
        self._ifxfile = unicode(self.ifxLineEdit.text())
        self._ofxfile = unicode(self.ofxLineEdit.text())
        self.process()
        self.writeOptionsFile()
        return

    @pyqtSignature("")
    def process(self):
        i = ret = 0
        self.progressBar.setMaximum(len(self._ifxfile_list))
        self.log("black", "*** Processing ***")
        if self.ifxAllCheckBox.isChecked():
            self.log ("black", "processing " + str(len(self._ifxfile_list)) + " files in: " + self._curdir)
            while i < len(self._ifxfile_list):
                self.progressBar.setValue(i)
                self.log ("black", str(i+1) + ':\t' + self._ifxfile_list[i])
                # process the current file. Returns -1 if failed
                ret += self.readwriteFile(self._ifxfile_list[i])
                i+=1
            self.log("black", "processed " + str(i+ret) + " of " +
                              str(len(self._ifxfile_list)) + " files in: " + self._curdir)
            self.progressBar.setValue(0)
        elif not self.ifxAllCheckBox.isChecked():
            self.log("black", "processing one file: " + self._ifxfile)
#            self.log("blue", "<b>process():</b> IFX File: " + self._ifxfile)
#            self.log("blue", "<b>process():</b> OFX File: " + self._ofxfile)
            self.readwriteFile(self._ifxfile)
            self.log("black", "processed 1 file in: " + self._ifxfile_dir)
        self.log("black", "*** Finished ***\n\n")
        self.progressBar.setValue(0)

    def readwriteFile(self, file):
        h = j = 0

        (ifx_dirName, ifx_fileName) = os.path.split(file)
        (ifx_fileBaseName, ifx_fileExtension)=os.path.splitext(ifx_fileName)
        ofxdir = ifx_dirName+ '/ofx/'

        # build ofx filename
        if not os.path.exists(ofxdir):
            os.makedirs(ofxdir)
        ofxfile = ofxdir + ifx_fileBaseName + '.ofx'
        if os.path.isfile(ofxfile):
            self.log("red", "<b>Warn:</b> OFX file \'" + ofxfile + "\' exists!\n")

        # build tree structure from ifxxml document
        try:
            gv.ifx_tree = et.parse(file)
        except et.XMLSyntaxError as e:
            self.log("red", "<b>Warn:</b> " + str(e))
            print "In file:", file
            print "Warning: ", e, '\n'
            return -1

        # process etree elements
        gv.ifx_root = gv.ifx_tree.getroot()
        read_accnt_ifxxml()

        # process transaction records
        print_account_details()

        if gv.ifxAccnt.ac_accttype == 'DDA':
            for trn in gv.ifx_root.iter('BankAcctTrnRec'):
                h += 1     #h: Number of BankAcctTrnRec entries, outer for loop counter
        elif gv.ifxAccnt.ac_accttype == 'CCA':
            for trn in gv.ifx_root.iter('CCAcctTrnRec'):
                h += 1

        create_ofx_base()

        while j < h:       #todo: beautify
            tmp_time = read_trans_ifxxml(j, gv.ifxAccnt.ac_accttype)
            gv.ifx_date_list.append(tmp_time)  # fill list to get ofx.dtstart and ofx.dtend later
            append_ofx_data()
            print_transaction_details()
            j+=1   # inner for loop counter

        append_ofx_date(gv.ifxAccnt.ac_accttype, gv.ifx_date_list)

        if self.ofxCheckBox.isChecked():
            try:
                gv.ofx.tree.write(ofxfile, encoding='ISO-8859-15')
                self.log("black", "Wrote: " + ofxfile)
            except:
                self.log("red", "<b>Err: </b> Unable to write ofxfile!")

        if self.saveIfxCheckBox.isChecked():
#            self.log("blue", "<b>readwriteFile(): </b>dirName: " + dirName + "\n")
#            self.log("blue", "<b>readwriteFile(): </b>fileName: " + fileName + "\n")
#            self.log("blue", "<b>readwriteFile(): </b>_ofxfile_dir: " + self._ofxfile_dir + "\n")
#            self.log("blue", "<b>readwriteFile(): </b>_ifxfile_dir: " + self._ifxfile_dir + "\n")
            savefile = self._ofxfile_dir + '/' + ifx_fileName
#            self.log("blue", "<b>readwriteFile(): </b>savefile: " + savefile + "\n")
            try:
                shutil.copy2(file, savefile)
            except (IOError, os.error), why:
                self.log("red", "<b>Err: </b> Unable to copy infile: " + why + "\n")
            if os.path.isfile(savefile):
                self.log("red", "<b>Warn: </b>IFXXML file \'" + savefile + "\' exists!\n")
            self.log("black", "Wrote: " + savefile)

        return 0

    def writeOptionsFile(self):
        optfile = os.getenv("HOME") + "/.py-konto"
#        self.log("blue", "<b>OptFile:</b> " + optfile)
        cp = ConfigParser.RawConfigParser()
        cp.add_section('Main')
        cp.set('Main', 'ofx_CB', self.ofxCheckBox.isChecked())
        cp.set('Main', 'ifx_save_CB', self.saveIfxCheckBox.isChecked())
        cp.set('Main', 'ifx_all_CB', self.ifxAllCheckBox.isChecked())
        cp.set('Main', 'ofxfile', self.ofxLineEdit.text())
        cp.set('Main', 'ifxfile', self.ifxLineEdit.text())
        cp.set('Main', 'curdir', self.dirLineEdit.text())
        # writing config file
        with open(optfile, 'wb') as conffile:
            cp.write(conffile)

    def readOptionsFile(self):
        optfile = os.getenv("HOME") + "/.py-konto"
        if not os.path.isfile(optfile):
            self.writeOptionsFile()
        cp = ConfigParser.RawConfigParser()
        try:
            cp.read(optfile)
            self._curdir = cp.get('Main', 'curdir')
            #self._ifxfile = cp.get('Main', 'ifxfile')
            self._ofxfile = cp.get('Main', 'ofxfile')
            self.ifxAllCheckBox.setChecked(cp.getboolean('Main', 'ifx_all_CB'))
            self.saveIfxCheckBox.setChecked(cp.getboolean('Main', 'ifx_save_CB'))
            self.ofxCheckBox.setChecked(cp.getboolean('Main', 'ofx_CB'))
#            self.log("blue", "<b>readOptionsFile():</b> _curdir: " + self._curdir)
#            self.log("blue", "<b>readOptionsFile():</b> ifx_all_CB: " + unicode(self.ifxAllCheckBox.isChecked()))
#            self.log("blue", "<b>readOptionsFile():</b> ifx_save_CB: " + unicode(self.saveIfxCheckBox.isChecked()))
#            self.log("blue", "<b>readOptionsFile():</b> ofx_CB: " + unicode(self.ofxCheckBox.isChecked()))
            return True
        except:
            self.log("red", "<b>Warn:</b> Cannot process config file" + optfile)
            return False

    def log(self, color, msg):
        self.logTextEdit.append(("<font color=%s>" % color) + msg + "</font>")

#### Begin __main__ ####
if __name__ == "__main__":

    class glb_var:
        ifxAccnt = ''
        ifxTrans = ''
        ifx_date_list = []
        ofx = ''
        ifx_root = ''
        ifxxml_file = []    #: ifxxml files to be processed
        ofx_file = []       #: ofx file to output
        ifxdoc = ''   #: current ifxxml file to be processed
        bprint_account_details = False   #: set to True to output to konsole
        bcreate_ofx = False # set to True if ofx file(s) should be created in current dir
        bofxwrite = True    #bofxwrite: write ofx file or not (user input if file exists)
        bprint_transaction_details = False   #: set to True to output to konsole
        ball_files = False  #: import all files in given dir
        bshow_data = False   #: set to True to show transactions in konsole
    class Trans:
        def __init__(self, **kwds):
            self.__dict__.update(kwds)
    class Accnt:
        def __init__(self, **kwds):
            self.__dict__.update(kwds)
    class Ofx:
        def __init__(self, **kwds):
            self.__dict__.update(kwds)

    # constants
    BANKID = '12000'    # ID of Bank-Austria

    gv = glb_var
    gv.ifxAccnt = Accnt
    gv.ifxTrans = Trans
    gv.ofx = Ofx

    def process_cli_args():
        """
        processing commandline arguments
        @rtype: none
        """
        parser = argparse.ArgumentParser(description='''Process an ifxxml file from UniCredit/BankAustria (AT)
        and convert it to ofx. (Optionally insert the values into a MYSQL Database.)''')
        parser.add_argument('filename', action="store", help="IFXXML file to open or \'all\'")
        args = parser.parse_args()
        return args.filename

    def normalize_whitespace(text):
        """
        remove unneeded whitespace in memo fields
        @type    text: string
        @param   text: the string to remove ws
        @rtype:  string
        @return: beautified @text
        """
        return ' '.join(text.split())

    def format_time(time):
        """
        formats times to use in database
        @type   time: string
        @param  time: string Date read from ifxxml file
        @rtype:  string, string
        @return: date modified to suite: ofx file @tmp_time, mySQL @us_time
        """
        tmp_time = string.split(time, ".")
        rtime = tmp_time[2] + '-' + tmp_time[1] + '-' + tmp_time[0]
        return rtime

    def buildIfxFileTree(path):
        """
        builds a list with ifxxml files in current directory
        @return filelist: (list)
        """
        i = 0   #i: number of files in dir
        filelist = []
        # write infiles into document list
        for infile in glob.glob( os.path.join(path, '*.ifxxml') ):
            filelist.append(infile)
            i += 1
        print "buildIfxFileTree(): path = " + path  # + '/*.ifxxml'
        return filelist

    def read_accnt_ifxxml():
        """
        fills tuples ifxTrans and ifxAccnt with values from ifx document
        @rtype: none
        """
        if gv.ifx_root.find('BankSvc').getchildren()[0].tag == 'DepAcctTrnInqRs':
            gv.ifxAccnt.ac_accttype = 'DDA'
            gv.ifxAccnt.ac_accountid = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/DepAcctRec/AcctId').text
            gv.ifxAccnt.ac_accountowner = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/DepAcctRec/Memo').text
            gv.ifxAccnt.ac_curcode = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/DepAcctRec/AcctCur').text
            gv.ifxAccnt.ac_effdt = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/EffDt').text
        elif gv.ifx_root.find('BankSvc').getchildren()[0].tag == 'CCAcctStmtInqRs':
            gv.ifxAccnt.ac_accttype = 'CCA'
            gv.ifxAccnt.ac_accountid = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctRec/AcctId').text
            gv.ifxAccnt.ac_accountowner = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctRec/Memo').text
            gv.ifxAccnt.ac_curcode = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctRec/AcctCur').text
            gv.ifxAccnt.ac_effdt = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/EffDt').text
            gv.ifxAccnt.ac_ledger = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctRec/AcctBal[1]/CurAmt/Amt').text
            gv.ifxAccnt.ac_avail = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctRec/AcctBal[0]/CurAmt/Amt').text

    def read_trans_ifxxml(i, typ):
        """
        get transaction details from ifxxml file
        @type   i: int
        @param  i: Value for iter through ifxxml file nodes
        @type   typ: string
        @param  typ: CCA or DDA Account
        @rtype: string
        @return tmp_time: used to fill ofx.dtstart and ofx.dtend
        """
        if typ == "DDA":
            gv.ifxTrans.tr_type = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/BankAcctTrnRec[' +str(i)+ ']/TrnType').text
            gv.ifxTrans.tr_posteddt = format_time(gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/BankAcctTrnRec['+str(i)+ ']/PostedDt').text)
            gv.ifxTrans.tr_effdt = format_time(gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/BankAcctTrnRec[' +str(i)+ ']/EffDt').text.replace(' ', ''))
            gv.ifxTrans.tr_amt = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/BankAcctTrnRec[' +str(i)+ ']/CurAmt/Amt').text.replace(',', '.')
            gv.ifxTrans.tr_curcode = gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/BankAcctTrnRec[' +str(i)+ ']/CurAmt/CurCode').text
            gv.ifxTrans.tr_memo = normalize_whitespace(gv.ifx_root.find('BankSvc/DepAcctTrnInqRs/BankAcctTrnRec[' +str(i)+ ']/Memo').text)
            calc_md5()
        elif typ == "CCA":
            gv.ifxTrans.tr_type = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctTrnRec[' +str(i)+ ']/TrnType').text
            gv.ifxTrans.tr_posteddt = format_time(gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctTrnRec['+str(i)+ ']/PostedDt').text)
            gv.ifxTrans.tr_effdt = gv.ifxTrans.tr_posteddt      # for calculating md5 hash
            gv.ifxTrans.tr_amt = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctTrnRec[' +str(i)+ ']/CurAmt/Amt').text.replace(',', '.')
            gv.ifxTrans.tr_curcode = gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctTrnRec[' +str(i)+ ']/CurAmt/CurCode').text
            gv.ifxTrans.tr_memo = normalize_whitespace(gv.ifx_root.find('BankSvc/CCAcctStmtInqRs/CCAcctTrnRec[' +str(i)+ ']/Memo').text)
            calc_md5()

        return gv.ifxTrans.tr_effdt.replace('-', '')

    def print_account_details():
        """
        print account details to console
        @rtype: none
        """
        form.log ("grey", "ACCOUNT DETAILS")
#        log ("grey", " ("int. DB ID   : %s" % gv.ifxTrans.tr_account)
        form.log ("grey", "Account Type : %s" % gv.ifxAccnt.ac_accttype)
        form.log ("grey", "Account Cur  : %s" % gv.ifxAccnt.ac_curcode)
        form.log ("grey", "Account ID   : %s" % gv.ifxAccnt.ac_accountid)
        form.log ("grey", "Account owner: %s" % gv.ifxAccnt.ac_accountowner)
        form.log("grey", " ")

    def print_transaction_details():
        """
        prints out Transaction Details
        @rtype: none
        """
        form.log("grey", "TRANSACTION DETAILS")
#        print ("Trans AcctId : %s" % gv.ifxTrans.tr_account)
        form.log("grey", "Trans Type   : %s" % gv.ifxTrans.tr_type)
        form.log("grey", "Trans Posted : %s" % gv.ifxTrans.tr_posteddt)
        form.log("grey", "Trans Eff    : %s" % gv.ifxTrans.tr_effdt)
        form.log("grey", "Trans Amt    : %s" % gv.ifxTrans.tr_amt)
        form.log("grey", "Trans Cur    : %s" % gv.ifxTrans.tr_curcode)
        form.log("grey", "Trans Memo   : %s" % gv.ifxTrans.tr_memo)
        form.log("grey", " ")

    def calc_md5():
        """
        calculate UID of transaction set, bcause BankAustria doesn't provide it
        """
        md5 = hashlib.md5()
        md5.update(gv.ifxTrans.tr_effdt)
        md5.update(unicode(gv.ifxTrans.tr_memo).encode('ASCII', 'replace'))
        md5.update(gv.ifxTrans.tr_amt)
        gv.ifxTrans.tr_md5 = md5.hexdigest()

    def create_ofx_base():
        """
        Inserts base ifx data into ofx tree
        @return ofx.tree, ofx.stmttrnrs:
        """
        gv.ofx.root = et.Element('OFX')
        gv.ofx.tree = et.ElementTree(gv.ofx.root)
        # Begin SIGNONMSGSVRSV1
        gv.ofx.signon = et.SubElement(gv.ofx.root, 'SIGNONMSGSRSV1')
        gv.ofx.sonrs = et.SubElement(gv.ofx.signon, 'SONRS')
        gv.ofx.status = et.SubElement(gv.ofx.sonrs, 'STATUS')
        gv.ofx.code = et.SubElement(gv.ofx.status, 'CODE')
        gv.ofx.code.text = '0'
        gv.ofx.severity = et.SubElement(gv.ofx.status, 'SEVERITY')
        gv.ofx.severity.text = 'INFO'
        gv.ofx.dtserver = et.SubElement(gv.ofx.sonrs, 'DTSERVER')
        gv.ofx.lang = et.SubElement(gv.ofx.sonrs, 'LANGUAGE')
        gv.ofx.lang.text = 'ENG'
        # End SIGNONMSGSRSV1
        # Begin BANKMSGSRSV1
        gv.ofx.bankmsgsrs = et.SubElement(gv.ofx.root, 'BANKMSGSRSV1')
        # Begin STMTRNRS
        gv.ofx.stmttrnrs = et.SubElement(gv.ofx.bankmsgsrs, 'STMTTRNRS')
        gv.ofx.trnuid = et.SubElement(gv.ofx.stmttrnrs, 'TRNUID')
        gv.ofx.trnuid.text = '1'
        gv.ofx.status = et.SubElement(gv.ofx.stmttrnrs, 'STATUS')
        gv.ofx.code = et.SubElement(gv.ofx.status, 'CODE')
        gv.ofx.code.text = '0'
        gv.ofx.severity = et.SubElement(gv.ofx.status, 'SEVERITY')
        gv.ofx.severity.text = 'INFO'
        gv.ofx.dtserver.text = gv.ifxAccnt.ac_effdt + '000000'
        gv.ofx.stmtrs = et.SubElement(gv.ofx.stmttrnrs, 'STMTRS')
        gv.ofx.curdef = et.SubElement(gv.ofx.stmtrs, 'CURDEF')
        gv.ofx.curdef.text = gv.ifxAccnt.ac_curcode
        gv.ofx.bankacctfrom = et.SubElement(gv.ofx.stmtrs, 'BANKACCTFROM')
        gv.ofx.bankid = et.SubElement(gv.ofx.bankacctfrom, 'BANKID')
        gv.ofx.bankid.text = BANKID
        gv.ofx.acctid = et.SubElement(gv.ofx.bankacctfrom, 'ACCTID')
        gv.ofx.acctid.text = gv.ifxAccnt.ac_accountid
        gv.ofx.accttype = et.SubElement(gv.ofx.bankacctfrom, 'ACCTTYPE')
        gv.ofx.accttype.text = "CHECKING"
        gv.ofx.banktranlist = et.SubElement(gv.ofx.stmtrs, 'BANKTRANLIST')
        gv.ofx.dtstart = et.SubElement(gv.ofx.banktranlist, 'DTSTART')
        gv.ofx.dtend = et.SubElement(gv.ofx.banktranlist, 'DTEND')

        return gv.ofx.tree, gv.ofx.stmttrnrs

    def append_ofx_data():
        """
        Inserts iterable ifx data into ofx tree
        @rtype: none
        """
        gv.ofx.stmttrn = et.SubElement(gv.ofx.banktranlist, 'STMTTRN')
        gv.ofx.trntype = et.SubElement(gv.ofx.stmttrn, 'TRNTYPE')
        gv.ofx.trntype.text = 'CHECK'
        gv.ofx.dtposted = et.SubElement(gv.ofx.stmttrn, 'DTPOSTED')
        gv.ofx.dtposted.text = gv.ifxTrans.tr_posteddt.replace('-', '')
        gv.ofx.trnamt = et.SubElement(gv.ofx.stmttrn, 'TRNAMT')
        gv.ofx.trnamt.text = gv.ifxTrans.tr_amt
        gv.ofx.fitid = et.SubElement(gv.ofx.stmttrn, 'FITID')
        gv.ofx.fitid.text = gv.ifxTrans.tr_md5
        gv.ofx.memo = et.SubElement(gv.ofx.stmttrn, 'MEMO')
        gv.ofx.memo.text = gv.ifxTrans.tr_memo

    def append_ofx_date(type, date):
        """
        Inserts first and last transaction date of ifx file into ofx tree
        @param date:
        @rtype: none
        """
        gv.ofx.dtstart.text = min(date)
        gv.ofx.dtend.text = max(date)

        gv.ofx.ledgerbal = et.SubElement(gv.ofx.stmtrs, 'LEDGERBAL')
        gv.ofx.balamt = et.SubElement(gv.ofx.ledgerbal, 'BALAMT')
        if type == 'DDA':
            gv.ofx.balamt.text = '0'
        elif type == 'CCA':
            gv.ofx.balamt.text = gv.ifxAccnt.ac_ledger
        gv.ofx.dtasof = et.SubElement(gv.ofx.ledgerbal, 'DTASOF')
        gv.ofx.dtasof.text = gv.ifxAccnt.ac_effdt
        gv.ofx.availbal = et.SubElement(gv.ofx.stmtrs, 'AVAILBAL')
        gv.ofx.balamt = et.SubElement(gv.ofx.availbal, 'BALAMT')
        if type == 'DDA':
            gv.ofx.balamt.text = '0'
        elif type == 'CCA':
            gv.ofx.balamt.text = gv.ifxAccnt.ac_avail
        gv.ofx.dtasof = et.SubElement(gv.ofx.availbal, 'DTASOF')
        gv.ofx.dtasof.text = gv.ifxAccnt.ac_effdt

    app = QApplication(sys.argv)
    gv.ifxdoc = process_cli_args()
    form = mainDialog(gv.ifxdoc)
    form.show()
    #form.log("blue", "<b>debug: args:</b> " + gv.ifxdoc)
    app.exec_()
